/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { compile, match, parse, pathToRegexp, tokensToFunction, regexpToFunction, tokensToRegexp } from "./pathToRegexp.js";

const forNumber = 1000

// Compile converts path rules into a function that concatenates incoming parameters into a valid path
function compile_test() {
  let number;
  let startTime = Date.now()
  for (let i = 0; i < forNumber; i++) {
    const toPath = compile('/user/:id', {
      encode: encodeURIComponent
    });
    number = toPath({
      id: 123
    })
  }
  let endTime = Date.now()
  // print(`result: ${result[0]}`)
  if (number != "/user/123") {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_Compile: ${endTime - startTime} ms`)
}
//Compile将路径规则转换为一个函数，该函数可以将传入的参数拼接为一个有效的路径。
function compile_test_02() {
  let number;
  let startTime = Date.now()
  for (let i = 0; i < forNumber * 10; i++) {
    const toPath = compile("/:segment+");
    number = toPath({ segment: ["a", "b", "c"] });
  }
  let endTime = Date.now()
  if (number != "/a/b/c") {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_Compile(List): ${endTime - startTime} ms`)
}
// According to the specified rules, after a series of transformations, return a function used to convert the path into a parameter.
function match_test() {
  let number;
  let startTime = Date.now()
  for (let i = 0; i < forNumber; i++) {
    const fn = match('/user/:id', {
      decode: decodeURIComponent
    });
    number = fn('/user/123');
  }
  let endTime = Date.now()
  if (JSON.stringify(number) != `{"path":"/user/123","index":0,"params":{"id":"123"}}`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_Match: ${endTime - startTime} ms`)

}
//match自定义匹配命名参数
function match_test_02() {
  let number;
  let startTime = Date.now()
  for (let i = 0; i < forNumber; i++) {
    const fn = match("/users/:id/:tab(home|photos|bio)", {
      decode: decodeURIComponent,
    });

    number = fn("/users/1234/photos");
  }
  let endTime = Date.now()
  if (JSON.stringify(number) != `{"path":"/users/1234/photos","index":0,"params":{"id":"1234","tab":"photos"}}`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_Match(Custom): ${endTime - startTime} ms`)

}
//匹配经过特殊编码的参数
function match_test_03() {
  let number;
  let startTime = Date.now()
  for (let i = 0; i < forNumber * 10; i++) {
    const fn = match("/café", { encode: encodeURI });

    number = fn("/caf%C3%A9");
  }
  let endTime = Date.now()
  if (JSON.stringify(number) != `{"path":"/caf%C3%A9","index":0,"params":{}}`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_Match(encode): ${endTime - startTime} ms`)

}
// The parsing function is responsible for parsing the passed path string and returning the parsing result string and key list for each parameter.
function parse_test() {
  let tokens;
  let startTime = Date.now();
  for (let i = 0; i < forNumber * 10; i++) {
    tokens = parse('/route/:foo/(.*)');
  }
  let endTime = Date.now();

  if (tokens.length != 3) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_Parse: ${endTime - startTime} ms`)
}

// Define by adding a colon before the parameter name, for example: foo,: bar. Using exec can resolve named parameters that meet the conditions in the path.
function pathToRegexp_test() {
  let startTime = Date.now();
  let regexp;
  for (let i = 0; i < forNumber * 10; i++) {
    regexp = pathToRegexp("/:foo/:bar");
  }
  let endTime = Date.now();

  let result = regexp.exec('/test/route')
  if (JSON.stringify(result) != `["/test/route","test","route"]`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_pathToRegexp: ${endTime - startTime} ms`)
}
//通过包装在{}里面的参数来实现为路径参数添加自定义的前后缀。
function pathToRegexp_test_02() {
  let startTime = Date.now();
  let regexp;
  for (let i = 0; i < forNumber; i++) {
    regexp = pathToRegexp("/:attr1?{-:attr2}?{-:attr3}?");
  }
  let endTime = Date.now();

  let result = regexp.exec("/test,test,,");
  if (result != `/test,test,,,test,test,,,,`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_pathToRegexp({}): ${endTime - startTime} ms`)
}
//(.*)，用以匹配任意参数。
function pathToRegexp_test_03() {
  let startTime = Date.now();
  let regexp;
  for (let i = 0; i < forNumber; i++) {
    regexp = pathToRegexp("/:foo/(.*)");
  }
  let endTime = Date.now();

  let result = regexp.exec("/test/route");
  if (result != `/test/route,test,route`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_pathToRegexp(.*): ${endTime - startTime} ms`)
}
// Convert the token to a path function.
function tokensToFunction_test() {
  let str = parse('/user/:id/:uname/:age/:Gender')
  let options = {
    encode: encodeURIComponent
  }
  let path;
  let startTime = Date.now();
  for (let i = 0; i < forNumber * 10; i++) {
    path = tokensToFunction(str, options)({
      id: 123,
      uname: 'SISO',
      age: 18,
      Gender: "男"
    })
  }

  let endTime = Date.now();
  if (path != `/user/123/SISO/18/%E7%94%B7`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_TokensToFunction(Token[], object): ${endTime - startTime} ms`)
}

// Create a path matching function from the output of "path to regexp".
function regexpToFunction_test() {
  let keys = [];
  let str = '/user/:id/:uname/:age/:Gender';
  let options = {
    decode: decodeURIComponent
  };
  let re = pathToRegexp(str, keys, options)
  let result;
  let startTime = Date.now();
  for (let i = 0; i < forNumber * 10; i++) {
    result = regexpToFunction(re, keys, options)('/user/123/赵四/35/女')
  }
  let endTime = Date.now();
  if (JSON.stringify(result) != `{"path":"/user/123/赵四/35/女","index":0,"params":{"id":"123","uname":"赵四","age":"35","Gender":"女"}}`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_RegexpToFunction(RegExp, Key[], object): ${endTime - startTime} ms`)
}

// Convert token to RegExp
function tokensToRegexp_test() {
  let keys = [];
  let tokens = parse('/user/:id/:uname/:age/:Gender');
  let resultRegExp;
  let startTime = Date.now()
  for (let i = 0; i < forNumber * 10; i++) {
    resultRegExp = tokensToRegexp(tokens, keys)
  }
  let endTime = Date.now()
  if (!(resultRegExp instanceof RegExp)) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_TokensToRegexp(Token[], Key[]?, object): ${endTime - startTime} ms`)
}

function exec_test() {
  const regexp = pathToRegexp("/:foo/(.*)");
  let resultRegExp;
  let startTime = Date.now()
  for (let i = 0; i < forNumber * 10; i++) {
    resultRegExp = regexp.exec('/test/route');
  }
  let endTime = Date.now()
  if (resultRegExp != `/test/route,test,route`) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_exec: ${endTime - startTime} ms`)
}
function test_test() {
  const re = pathToRegexp('/caf\u00E9');
  const input = encodeURI('/cafe\u0301');
  let resultRegExp;
  let startTime = Date.now()
  for (let i = 0; i < forNumber * 100; i++) {
    resultRegExp = re.test(input);
  }
  let endTime = Date.now()
  if (resultRegExp != false) {
    throw new Error('Inconsistent with expected results')
  }
  print(`pathToRegexp_test: ${endTime - startTime} ms`)
}

let loopCountForPreheat = 1;
for (let i = 0; i < loopCountForPreheat; i++) {
  compile_test()
  compile_test_02()
  match_test()
  match_test_02()
  match_test_03()
  parse_test()
  pathToRegexp_test()
  pathToRegexp_test_02()
  pathToRegexp_test_03()
  tokensToFunction_test()
  regexpToFunction_test()
  tokensToRegexp_test()
  exec_test()
  test_test()
}

ArkTools.waitAllJitCompileFinish();

compile_test()
compile_test_02()
match_test()
match_test_02()
match_test_03()
parse_test()
pathToRegexp_test()
pathToRegexp_test_02()
pathToRegexp_test_03()
tokensToFunction_test()
regexpToFunction_test()
tokensToRegexp_test()
exec_test()
test_test()